package edu.cqie.smartfarm.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import edu.cqie.smartfarm.constant.CommonConstant;
import edu.cqie.smartfarm.constant.MessageConstant;
import edu.cqie.smartfarm.constant.UserConstant;
import edu.cqie.smartfarm.dto.LoginDTO;
import edu.cqie.smartfarm.dto.UserDTO;
import edu.cqie.smartfarm.dto.UserQueryDTO;
import edu.cqie.smartfarm.dto.UserUpdateDTO;
import edu.cqie.smartfarm.entity.User;
import edu.cqie.smartfarm.mapper.UserMapper;
import edu.cqie.smartfarm.mapper.properties.JwtProperties;
import edu.cqie.smartfarm.result.PageVO;
import edu.cqie.smartfarm.service.IUserService;
import edu.cqie.smartfarm.utils.JwtUtil;
import edu.cqie.smartfarm.vo.UserVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author yyw
 * @since 2024-12-26
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    private final UserMapper userMapper;
    private final JwtProperties jwtProperties;
    private final StringRedisTemplate stringRedisTemplate;

    /**
     * 用户登录
     *
     * @param loginDTO
     * @return
     */
    @Override
    public String login(LoginDTO loginDTO) {
        // 查询用户是否存在
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(User::getUsername, loginDTO.getUsername())
                .eq(User::getPassword, DigestUtils.md5DigestAsHex(loginDTO.getPassword().getBytes()));
        User user = userMapper.selectOne(queryWrapper);
        if (user == null) {
            throw new RuntimeException(MessageConstant.USER_LOGIN_ERROR);
        }
        if (user.getStatus() == UserConstant.USER_STATUS_DISABLE) {
            throw new RuntimeException(MessageConstant.ACCOUNT_STOP);
        }
        // 进行登录
        log.info("用户登录:{}", loginDTO.getUsername());
        Map<String, Object> claims = new HashMap<>();
        claims.put(CommonConstant.USERNAME, loginDTO.getUsername());
        claims.put(CommonConstant.USER_ID, user.getId());
        String token = JwtUtil.createJWT(jwtProperties.getSecret(), jwtProperties.getExpireTime(), claims);
        //把token存储到redis中用于后续的校验
        ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
        operations.set(CommonConstant.PROJECT_NAME+":"+CommonConstant.USER_TOKEN+":"+token, user.getUsername(), jwtProperties.getExpireTime(), TimeUnit.HOURS);

        return token;
    }

    /**
     * 用户登出
     *
     * @param token
     * @return
     */
    @Override
    public String logout(String token) {
        ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
        Map<String, Object> claims = JwtUtil.parseJWT(jwtProperties.getSecret(), token);
        String username = (String) claims.get(CommonConstant.USERNAME);
        operations.getOperations().delete(CommonConstant.PROJECT_NAME+":"+CommonConstant.USER_TOKEN+":"+token);
        return username;
    }

    /**
     * 根据用户名获取用户信息
     *
     * @param userId
     * @return
     */
    @Override
    @Cacheable(value = CommonConstant.PROJECT_NAME + ":userInfo", key = "'user_' + #userId")
    public UserVO getByUserId(Integer userId) {
        User user = getById(userId);
        if (user == null) {
            throw new RuntimeException(MessageConstant.USER_NOT_FOUND);
        }
        UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
        return userVO;
    }

    /**
     * 添加用户
     *
     * @param userDTO
     */
    @Override
    @Transactional
    @CacheEvict(value = CommonConstant.PROJECT_NAME + ":userList", allEntries = true)
    public void add(UserDTO userDTO) {
        User user = BeanUtil.copyProperties(userDTO, User.class);
        // 判断手机号是否存在
        if(userDTO.getName() != null && userDTO.getName() != "" && userDTO.getName() != null){
            LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(User::getPhone, userDTO.getPhone());
            if (count(queryWrapper) > 0) {
                throw new RuntimeException(MessageConstant.PHONE_EXISTS);
            }
        }else {
            throw new RuntimeException(MessageConstant.PARAMETER_ERROR);
        }
        // 获取电话号码后六位为密码
        if (userDTO.getPhone() != null) {
            String substring = userDTO.getPhone().substring(userDTO.getPhone().length() - 6);
            user.setPassword(DigestUtils.md5DigestAsHex(substring.getBytes()));
        } else {
            user.setPassword(DigestUtils.md5DigestAsHex(userDTO.getPassword().getBytes()));
        }
        userMapper.insert(user);
        // 登录账号自动生成例如 YZ001, YZ002
        ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
        Integer number = Integer.valueOf(operations.get(CommonConstant.PROJECT_NAME+":user_number"));
        if (number != null){
            if (number < 10000) {
                user.setUsername("YZ" + String.format("%04d", number));
            } else {
                user.setUsername("YZ" + number);
            }
            operations.set(CommonConstant.PROJECT_NAME+":user_number", String.valueOf(number + 1));
        }else {
            if (user.getId() < 10000) {
                user.setUsername("YZ" + String.format("%03d", user.getId()));
            } else {
                user.setUsername("YZ" + user.getId());
            }
        }

        userMapper.updateById(user);
    }

    /**
     * 分页获取用户列表
     *
     * @param userQueryDTO
     * @return
     */
    @Override
    @Cacheable(value = CommonConstant.PROJECT_NAME + ":userList", key = "'page_' + #userQueryDTO.pageNumber + '_size_' + #userQueryDTO.pageSize + '_query_' + #userQueryDTO")
    public PageVO<UserVO> pageList(UserQueryDTO userQueryDTO) {
        // 创建Page对象用于分页查询，传入用户DTO中的页码和页面大小参数
        Page<User> page = new Page<>(userQueryDTO.getPageNumber(), userQueryDTO.getPageSize());

        // 创建LambdaQueryWrapper对象用于条件查询，根据用户DTO中的条件构建查询条件
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<User>()
                .like(userQueryDTO.getName() != null && userQueryDTO.getName() != "", User::getName, userQueryDTO.getName())
                .like(userQueryDTO.getPhone() != null && userQueryDTO.getPhone() != "", User::getPhone, userQueryDTO.getPhone())
                .eq(userQueryDTO.getStatus() != null, User::getStatus, userQueryDTO.getStatus());

        // 使用UserMapper的selectPage方法执行分页查询，传入Page对象和查询条件封装对象
        IPage<User> userPage = userMapper.selectPage(page, queryWrapper);
        // 获取查询结果中的记录列表
        List<User> records = userPage.getRecords();

        // 初始化UserVO列表为null
        List<UserVO> userVOList = null;

        // 如果查询结果不为空，则将查询结果转换为UserVO列表
        if (records.size() > 0) {
            userVOList = BeanUtil.copyToList(records, UserVO.class);
        }

        // 创建PageVO对象用于封装分页查询结果
        PageVO<UserVO> pageVO = new PageVO<>();

        // 设置分页信息到PageVO对象中
        pageVO.setCurrent(userPage.getCurrent());
        pageVO.setSize(userPage.getSize());
        pageVO.setTotal(userPage.getTotal());
        pageVO.setPages(userPage.getPages());
        pageVO.setRecords(userVOList);

        // 返回封装了分页查询结果的PageVO对象
        return pageVO;
    }

    @Override
    @CacheEvict(value = CommonConstant.PROJECT_NAME + ":userList", allEntries = true)
    public void updateInfo(UserUpdateDTO userUpdateDTO) {
        // 查看redis缓存中是否存在
        ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
        String s = operations.get(CommonConstant.PROJECT_NAME + ":userInfo::user_" + userUpdateDTO.getUserId());
        if (s != null){
            // 如果存在缓存则删除
            operations.getOperations().delete(CommonConstant.PROJECT_NAME + ":userInfo::user_" + userUpdateDTO.getUserId());
        }
        LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<User>()
                .eq(User::getId, userUpdateDTO.getUserId())
                .set(userUpdateDTO.getName() != null && userUpdateDTO.getName() != "", User::getName, userUpdateDTO.getName())
                .set(userUpdateDTO.getPhone() != null && userUpdateDTO.getPhone() != "", User::getPhone, userUpdateDTO.getPhone())
                .set(userUpdateDTO.getStatus() != null, User::getStatus, userUpdateDTO.getStatus());
        userMapper.update(wrapper);
    }

}
